package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.vo.ContentVO;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.entity.MaterialIdAndType;
import com.heima.wemedia.mapper.MaterialMapper;
import com.heima.wemedia.mapper.MaterialNewsMapper;
import com.heima.wemedia.mapper.NewsMapper;
import com.heima.wemedia.service.AutoScanService;
import com.heima.wemedia.service.NewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class NewServiceImpl extends ServiceImpl<NewsMapper, WmNews> implements NewsService {

    @Autowired
    private MaterialNewsMapper materialNewsMapper;
    @Autowired
    private MaterialMapper materialMapper;
    @Autowired
    private AutoScanService autoScanService;//自动审核

    /**
     * 素材列表查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResponseResult findNews(WmNewsPageReqDto dto) {
        // 1 分页查询的查询条件 这些是必须传的值 userid 以创建时间为倒序排序
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery()
                .eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId())
                .orderByDesc(WmNews::getPublishTime);

        //对条件进行判断

        //1.文章状态
        if (dto.getStatus() != null) {
            wrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //2.关键字
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            wrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //3.频道列表
        if (dto.getChannelId() != null) {
            wrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //4.发布时间
        if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            wrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }

        Page<WmNews> page = page(new Page<>(dto.getPage(), dto.getSize()),
                wrapper);

        PageResponseResult pageResponseResult = new PageResponseResult((int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal());
        pageResponseResult.setData(page.getRecords());
        return pageResponseResult;
    }

   /* @Override
    public PageResponseVO findNews2(WmNewsPageReqDto dto) {
        // 1 分页查询的查询条件 这些是必须传的值 userid 以创建时间为倒序排序
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery()
                .eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId())
                .orderByDesc(WmNews::getPublishTime);

        //对条件进行判断

        //1.文章状态
        if(dto.getStatus() != null){
            wrapper.eq(WmNews::getStatus,dto.getStatus());
        }
        //2.关键字
        if(StringUtils.isNotBlank(dto.getKeyword())){
            wrapper.like(WmNews::getTitle,dto.getKeyword());
        }
        //3.频道列表
        if(dto.getChannelId() != null){
            wrapper.eq(WmNews::getChannelId,dto.getChannelId());
        }
        //4.发布时间
        if(dto.getBeginPubDate() != null && dto.getEndPubDate() != null){
            wrapper.between(WmNews::getPublishTime,dto.getBeginPubDate(),dto.getEndPubDate());
        }

        Page<WmNews> page = page(new Page<>(dto.getPage(), dto.getSize()),
                wrapper);

        PageResponseVO vo = new PageResponseVO(page.getTotal(),
                page.getSize(),page.getCurrent(),page.getRecords());

        return vo;
    }*/

    /**
     * 文章内容上传
     *
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(WmNewsDto dto) {
        //转换为实体类
        WmNews wmNews = new WmNews();
        ////属性名 类型必须一致 把dto拷贝到实体类中
        BeanUtils.copyProperties(dto, wmNews);

        //处理自动选择封面
        String content = dto.getContent(); //[{},{type:image,value:url}]
        //用json反序列化 拿到文章内容进行封装 变成 文章内容的集合
        List<ContentVO> contentVOS = JSONArray.parseArray(content, ContentVO.class);

        //处理文章封面图片
        List<String> contentUrls = dealArticleImages(dto, wmNews, contentVOS);

        //保存数据库
        wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
        //判断提交时间
        //因为左边是short类型 右边是枚举 所以要拿枚举中的属性code
        if (dto.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            wmNews.setSubmitedTime(new Date());
        }

        if (dto.getId() == null) {
            //新增
            //创建时间
            wmNews.setCreatedTime(new Date());
            //上下架
            wmNews.setEnable((short) 1);

            save(wmNews);
        } else {
            //更新
            updateById(wmNews);
            //把文章和所有图片关联关系 删除
            materialNewsMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    //把文章和所有图片关联关系删除
                    .eq(WmNewsMaterial::getNewsId, dto.getId())
            );
        }

        //重建 图片和文章关联关系

        ArrayList<MaterialIdAndType> materialIdAndTypes = new ArrayList<>();
        //封面    将图片的url转换成集合
        List<MaterialIdAndType> coverDatas = dealImageAndNewsRelation(dto.getImages(), WemediaConstants.WM_COVER_REFERENCE);
        if (coverDatas != null) {
            materialIdAndTypes.addAll(coverDatas);
        }
        //内容
        List<MaterialIdAndType> contentDatas = dealImageAndNewsRelation(contentUrls, WemediaConstants.WM_CONTENT_REFERENCE);
        if (contentDatas != null) {
            materialIdAndTypes.addAll(contentDatas);
        }
        if (CollectionUtils.isNotEmpty(materialIdAndTypes)) {
            //有图片存入数据库中
            materialNewsMapper.insertBatch2(materialIdAndTypes, wmNews.getId());
        }
        //发布后判断是否需要审核
        if(dto.getStatus().equals(WmNews.Status.SUBMIT.getCode())){
            autoScanService.autoScan(wmNews);
        }
    }

    private List<MaterialIdAndType> dealImageAndNewsRelation(List<String> urls, short type) {

        if (CollectionUtils.isEmpty(urls)) {
            return null;
        }
        ArrayList<MaterialIdAndType> materialIdAndTypes = new ArrayList<>();

        //1.将url转换成id
        //select 所有字段 -> select id 这个实体类为素材表
        List<WmMaterial> wmMaterials = materialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                //多条数据用in
                .in(WmMaterial::getUrl, urls)
                //正常会返回许多字段 这个则只会返回id(减少返回数据 提升性能)
                .select(WmMaterial::getId)
        );
        ////通过Stream流转换为集合
        //所有素材id
        List<Integer> ids = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
        if (ids != null) {
            //遍历集合
            for (Integer coverId : ids) {
                //拿到这个图片的id给组装成对象
                MaterialIdAndType materialIdAndType = new MaterialIdAndType();
                //设置类型
                materialIdAndType.setType(type);
                //设置id
                materialIdAndType.setId(coverId);
                //添加到集合中
                materialIdAndTypes.add(materialIdAndType);
            }
        }

        //素材ids 文章id 类型type 批量写入数据库
        // materialNewsMapper.insertBatch(ids,wmNews.getId(),type);
        return materialIdAndTypes;

    }

    //处理文章图片
    private List<String> dealArticleImages(WmNewsDto dto, WmNews wmNews, List<ContentVO> contentVOS) {
        //for循环
//        Set<String> urls = new HashSet<>();
//        for (ContentVO contentVO : contentVOS) {
//            if(WemediaConstants.WM_NEWS_TYPE_IMAGE.equals(contentVO.getType())){
//                //图片
//                String url = contentVO.getValue();
//                urls.add(url);
//            }
//        }
//
//        List<String> urlList = new ArrayList<>(urls);

        // stream流 方式来改造代码 1.创建流 2.流运算(筛选 取值 去重) 3.输出集合 collect
        List<String> urls = contentVOS.stream()
                //筛选图片类型
                .filter(contentVO -> WemediaConstants.WM_NEWS_TYPE_IMAGE.equals(contentVO.getType()))
                //取值
                .map(ContentVO::getValue)
                //去掉重复的值
                .distinct()
                //输出集合
                .collect(Collectors.toList());
        //自动选择封面
        //判断如果是自动，获取内容中的图片作为封面
        if (Objects.equals(WemediaConstants.WM_NEWS_TYPE_AUTO, dto.getType())) {

            int size = urls.size();
            if (size >= 3) {
                //>=3张 取前三张 3图
                //sublist取头不取尾 0  1 2 正好三个
                dto.setImages(urls.subList(0, 3));
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            } else if (size > 0) {
                //1-2张 单图，取第一张
                dto.setImages(urls.subList(0, 1));
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            } else {
                //0张 无图
                dto.setImages(null);
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }

        }

        //处理数据库中的images(将前端的实体类传入到数据库中)
        //判断是有图还是无图
        if (CollectionUtils.isNotEmpty(dto.getImages())) {
            //用逗号分隔字符串，写入数据库实体类中
            //如果DTO中的图片是存在的 就通过用工具类通过,分隔来生成图片
            //用逗号分隔字符串,写入数据库实体类中
            String join = StringUtils.join(dto.getImages(), ",");
            //把最后的字符串放入数据库实体类中
            wmNews.setImages(join);
        }

        return urls;
    }
}
